#include "socket.h"

int ae_address_query4(ae_address_t* addr, const char* netname, unsigned short port, int address_size)
{
	int ret = -1;
	struct addrinfo *result;
	socket_addr* raddr = (socket_addr*)addr;

	if(raddr == NULL || netname == NULL || address_size < sizeof(struct sockaddr_in))
		return ret;

	if(getaddrinfo(netname, NULL, NULL, &result) == 0)
	{
		if(result->ai_family == AF_INET)
		{
			raddr->ipv4.sin_family = AF_INET;
			raddr->ipv4.sin_port = htons(port);
			memcpy(&raddr->ipv4.sin_addr, &((struct sockaddr_in*)result->ai_addr)->sin_addr, sizeof(raddr->ipv4.sin_addr));
			ret = 0;
		}
		else if(address_size >= sizeof(struct sockaddr_in6) && result->ai_family == AF_INET6) {
			raddr->ipv6.sin6_family = AF_INET6;
			raddr->ipv6.sin6_port = htons(port);
			memcpy(&raddr->ipv6.sin6_addr, &((struct sockaddr_in6*)result->ai_addr)->sin6_addr, sizeof(raddr->ipv6.sin6_addr));
			ret = 0;
		}
		freeaddrinfo(result);
	}
	return ret;
}

int ae_address_ip(ae_address_t* addr, char* ip, int size)
{
	int ret = -1;
	socket_addr* raddr = (socket_addr*) addr;

	if(raddr == NULL || ip == NULL || size < 1)
		return ret;

	if(raddr->sa.sa_family == AF_INET) {
		const char* ptr = inet_ntoa(raddr->ipv4.sin_addr);

		if((int)strlen(ptr) < size) {
			ret = 0;
			strcpy(ip, ptr);
		}
	}
	else {
#if defined(AE_WIN32)
		char* pos;
		DWORD need_length = size;

		if(WSAAddressToStringA((struct sockaddr*)&raddr->ipv6, sizeof(raddr->ipv6), NULL, ip, &need_length) == 0) {
			ret = 0;
			pos = strrchr(ip, ']');
			memmove(ip, ip + 1, pos - ip - 1);
			*--pos = '\0';
		}
#else
		if(inet_ntop(AF_INET6, &raddr->ipv6.sin6_addr, ip, size))
			ret = 0;
#endif
	}
	return ret;
}

int ae_address_port(ae_address_t* addr, unsigned short* port)
{
	socket_addr* raddr = (socket_addr*) addr;

	if(raddr == NULL)
		return -1;

	if(raddr->sa.sa_family == AF_INET)
		*port = ntohs(raddr->ipv4.sin_port);
	else if(raddr->sa.sa_family == AF_INET6)
		*port = ntohs(raddr->ipv6.sin6_port);
	else
		*port = 0;
	return 0;
}

int ae_address_string(ae_address_t* addr, char* address, int size)
{
	int ret = -1;
	socket_addr* raddr = (socket_addr*) addr;

	if(raddr == NULL || address == NULL || size < 1)
		return ret;

	if(raddr->sa.sa_family == AF_INET) {
		const char* ptr = inet_ntoa(raddr->ipv4.sin_addr);

		if(ptr && (int)strlen(ptr) + 6 < size) {
			ret = 0;
			sprintf(address, "%s:%d", ptr, ntohs(raddr->ipv4.sin_port));
		}
	}
	else {
#if defined(AE_WIN32)
		DWORD need_length = size;

		if(WSAAddressToStringA((struct sockaddr*)&raddr->ipv6, sizeof(raddr->ipv6), NULL, address, &need_length) == 0)
			ret = 0;
#else
		if(inet_ntop(AF_INET6, &raddr->ipv6.sin6_addr, address + 1, size - 8)) {
			ret = 0;
			address[0] = '[';
			sprintf(address + strlen(address), "]:%d", ntohs(raddr->ipv4.sin_port));
		}
#endif
	}
	return ret;
}
